#pragma once
#include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<cstring>
#include<string>
#include<functional>
#include"nocopy.hpp"
#include"Log.hpp"
#include"InetAddr.hpp"

using namespace log_ns;
using namespace std;

static const int gsockfd = -1;
static const uint16_t glocalport = 8888;
enum{
    SOCKET_ERROR=1,
    BIND_ERROR
};

using func_t = function<string(string)>;//定义一个回调函数,参数为string,返回值为string
// 一般服务器主要是用来进行网络数据读取和写入的。IO的
// 服务器IO逻辑 和 业务逻辑 解耦
class UdpServer:public nocopy
{
public:
    UdpServer(func_t func,uint16_t localport = glocalport):_sockfd(gsockfd),_localport(localport),_isrunning(false),_func(func)
    {

    }

    void InitServer()//网络初始化
    {
        //1.创建套接字文件
        _sockfd = ::socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd<0)
        {
            LOG(FATAL,"socket error\n");
            exit(SOCKET_ERROR);
        }
        LOG(DEBUG,"socket create success,_sockfd:%d\n",_sockfd);//0，1，2被占用了，所以fd是3

        //2.进行bind绑定
        struct sockaddr_in local;//网络通信
        memset(&local,0,sizeof(local));//结构体清空
        local.sin_family = AF_INET;
        local.sin_port = htons(_localport);//主机转网络序列，互相进行通信
        //local.sin_addr.s_addr = inet_addr(_localip.c_str());//需要4字节ip，需要网络序列的ip
        local.sin_addr.s_addr = INADDR_ANY;//服务器端进行任意ip地址绑定

        int n = ::bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
        if(n<0)
        {
            LOG(FATAL,"bind error\n");
            exit(BIND_ERROR);
        }
        LOG(DEBUG,"socket bind success\n");
    }

    void Start()
    {
        _isrunning=true;
        char inbuffer[1024];
        while(_isrunning)//服务是一个死循环，不会关闭的，除非自己终止进程
        {
            struct sockaddr_in peer;//客户端
            socklen_t len = sizeof(peer);                                         //谁发的（客户端）
            ssize_t n = recvfrom(_sockfd, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr *)&peer, &len);//从客户端收的消息；(struct sockaddr *)&peer, &len是shuru输出型参数
            if(n>0)
            {
                InetAddr addr(peer);//创建一个转主机序列化的类
                inbuffer[n]=0;
                cout<<"["<<addr.Ip()<<":"<<addr.Port()<<"]"<<inbuffer<<endl;

                string result = _func(inbuffer);//回调函数还会返回
                                                                            //发给谁（客户端）
                sendto(_sockfd,result.c_str(),result.size(),0,(struct sockaddr *)&peer, len);//将消息从服务器发送给客户端;(struct sockaddr *)&peer, len输入型参数
            }
        }
    }

    ~UdpServer()
    {
        if(_sockfd > gsockfd) ::close(_sockfd);
    }
private:
    int _sockfd;
    uint16_t _localport;//端口号16字节
    //string _localip;//ip地址
    bool _isrunning;
    func_t _func;
};